[爬虫] python3分析《战狼2》豆瓣影评

这是一篇关于python3爬虫的练手项目

Posted by Leung ZhengHua on 2017-08-17

本文总点击量

如果你是第一次阅读本文,你可能会对以下扫盲贴感兴趣:
有趣的练手项目《python3网络爬虫入门
崔庆才|静觅的《Python爬虫学习系列教程
Python selenium —— 一定要会用selenium的等待,三种等待方式解读

你可以还会关心以下的链接:
PhantomJS下载地址
谷歌浏览器驱动下载地址

你可能还想折腾比较前沿的headless:
Chrome 也支持 headless testing 啦


数据抓取

打开战狼2的短评网址,目标URL为 https://movie.douban.com/subject/26363254/comments?start=0&limit=20 ,每个电影都会有一个唯一的ID,这里战狼2的ID是26363254,start=0表示评论从第0条开始,limit=20表示每页显示20条短评。
打开审查元素中的Elements,找到我们感兴趣的评论区域,它们的结构体是这样的:

我们可以根据这个结构体的标签逐步剥离评论内容出来,先提取 < div class=”comment” > 标签块,再提取每个标签块里面的 < p class > 标签块的文字评论内容。python3代码如下:

单页评论抓取

1
2
3
4
5
6
7
8
9
10
11
12
from urllib import request
from bs4 import BeautifulSoup as bs
requrl="https://movie.douban.com/subject/26363254/comments?start=0&limit=20"
resp = request.urlopen(requrl)
html_data = resp.read().decode('utf-8')
soup = bs(html_data, 'html.parser')
comment_div_lits = soup.find_all('div', class_='comment') #找出标签div的评论
eachCommentList = []; #用来装载评论的空列表
for item in comment_div_lits:
if item.find_all('p')[0].string is not None: #找出标签p的评论
eachCommentList.append(item.find_all('p')[0].string)
print(eachCommentList)

利用selenium爬取全部评论

selenium是自动化测试的工具,利用selenium和phantom可以模拟真实用户在无界面浏览器的网页浏览操作,类似你闭着眼睛不知疲倦上网而且能够一目百行。据闻使用无头浏览器phantom爬取豆瓣时,会出现输入验证码的障碍;测试中发现如果使用selenium+谷歌浏览器,非常顺利不需要输入验证码,可以时刻监控浏览器或者停下来手动操控,selenium虽然慢,可是开发效率高啊,对于不看重效率的自娱自乐的爬虫我觉得完全足够了,所以现在先用比较简单的谷歌浏览器试验一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#爬取12万条评论
from bs4 import BeautifulSoup as bs
from selenium import webdriver
driver = webdriver.Chrome('F:\E盘文件\重要软件\chrome_drive\chromedriver_win32\chromedriver.exe') #这里是你的浏览器驱动exe文件存储位置
#driver = webdriver.PhantomJS(executable_path="C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python36\\Scripts\\phantomjs.exe")
driver.maximize_window()
driver.get("https://movie.douban.com/subject/26363254/comments?start=0&limit=20")
driver.implicitly_wait(20)
#登录
#这里需要打开浏览器界面,手动登录你的豆瓣账号,否则下文会提示你没有登录没有权限
eachCommentList = [];i=0
#控制循环条件
while i<10000:
new_page = driver.page_source
# 对新的页面提取该页面评论文本
soup = bs(new_page, 'html.parser')
comment_div_lits = soup.find_all('div', class_='comment')
for item in comment_div_lits:
if item.find_all('p')[0].string is not None:
eachCommentList.append(item.find_all('p')[0].string)
#print(eachCommentList)
# 点击下一页
element2 = driver.find_element_by_xpath("//a[@class='next']")
sentinel=driver.current_url
element2.click()
if sentinel== driver.current_url or i>10000:
st=input()
if st== 'berak':
break
i=i+1
print(driver.current_url)
#这里可以添加一行代码,选择保存评论文本数据

数据清洗

对上面得到的评论文本,我需要去其标点符号,删其语气词,取其分割位置,算其出现频数,然后才舒服。停词文档的选择很重要啊,我发现用这份停词文档处理得到的词语依然有些没有用的词,比如“都”,“还”;另外停词文件中应不应该包含标点符号,事先清洗掉标点符号的做法是出于什么理由?

你可能要先下好中文停词txt文件,可以百度之

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import re
import jieba # 分词包
import pandas as pd
import numpy #numpy计算包
def clean(result,stopwords):
comments = ''
for k in range(len(result)):
comments = comments + (str(result[k])).strip()
pattern = re.compile(r'[\u4e00-\u9fa5]+')
filterdata = re.findall(pattern, comments)
cleaned_comments = ''.join(filterdata)
segment = jieba.lcut(cleaned_comments)
words_df = pd.DataFrame({'segment': segment})
#需要下载一个停词txt文件,过滤掉语气词等等
stopwords = pd.read_csv(stopwords, index_col=False, quoting=3, sep="\t", names=['stopword'],
encoding='utf-8') # quoting=3全不引用
words_df = words_df[~words_df.segment.isin(stopwords.stopword)]
return words_df
stopwords = 'E:\\blog\\assets\\stopwords-list\\stop_words_zh_UTF-82.txt' #这里可以从其他地方导入停词的文本
result2 = clean(result=eachCommentList, stopwords=stopwords)
words_stat = result2.groupby(by=['segment'])['segment'].agg({"计数": numpy.size})
words_stat = words_stat.reset_index().sort_values(by=["计数"], ascending=False) # 词汇统计

词云展示

用python也可以做词云,然而用R做词云感觉才更GEEK更容易更好看。顺便也可以测试一下使用python调用R语句绘图,这比调用一般的R语句又要晦涩一点。
由于wordcloud2对中文的词云支持不太好,我将目光转向了略显粗糙的第一版wordcloud。

你可能需要在RStudio中安装好对应的wordcloud包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#使用R的词云
import rpy2.robjects as robjects
from rpy2.robjects import pandas2ri #需要导入pandas2ri模块,并使其激活才能转换pandas数据框为R的数据框
pandas2ri.activate()
mydata=robjects.r['data.frame'](x=words_stat["segment"],y=words_stat["计数"])
# 在R进程里面执行R脚本
robjects.globalenv['mydata']=mydata
robjects.r('''
f=function(mydata) {
library(wordcloud)
n=ifelse(nrow(mydata)>200,200,nrow(mydata))
my_cloud=wordcloud(mydata[1:n,1],mydata[1:n,2], random.color = T,colors = c("purple","sienna","springgreen",
"tomato","violetred4","seagreen3"))
#my_path <- htmltools::html_print(my_cloud) # saves html in temp directory
#print(my_path) # the location of the html file.
}
#path=f(mydata)
#class(mydata)
#print(mydata[1:10,1])
library(wordcloud)
f(mydata) #在我的电脑上可以自动打开device窗口
''')

把这个流程封装一下,以后看电影之前就可以用这个黑科技看一下电影能不能吸住你的眼球,反正又不是剧透,看完还能发个微博装装逼。:)